#pragma once

#include "QuestLog.h"

class Creature;

class QuestStorage
{
public:
	QuestStorage(Player* pOwner);
	~QuestStorage();

	void Update();

	void AddQuestLog(QuestLog* pQuestLog);
	void RemoveQuestLog(QuestLog* pQuestLog);

	void SetLevelDirty();
	void SetQuestStatusDirty(uint32 questTypeID);
	void SetChequeValueDirty(ChequeType chequeType);
	void SetItemCountDirty(uint32 itemTypeID);

	void OnTalkNPC(Creature* pCreature);
	void OnKillCreature(Creature* pCreature);
	void OnHaveCheque(ChequeType chequeType, uint64 chequeValue, CHEQUE_FLOW_TYPE flowType, params<uint32> flowParams);
	void OnHaveItem(uint32 itemTypeID, uint32 itemCount, ITEM_FLOW_TYPE flowType, params<uint32> flowParams);
	void OnUseItem(uint32 itemTypeID, uint32 itemCount, uint32 actionUniqueKey);
	void OnPlayStory(uint32 questTypeID, bool isSucc);

	void SetQuestFinished(uint32 questTypeID);

	void EventCleanRepeatQuests(QuestRepeatType questRepeatType);

	void AddToFinishedQuest(const QuestPrototype* pQuestProto);
	bool IsQuestFinished(const QuestPrototype* pQuestProto) const;
	bool IsQuestHasFinished(const QuestPrototype* pQuestProto) const;
	bool IsQuestHasFinished(uint32 questTypeID) const;

	QuestLog* GetQuestLogByKey(uint32 questUniqueKey) const;
	QuestLog* GetQuestLogByEntry(uint32 questTypeID) const;

	uint32 GetQuestLackItemCount(uint32 questTypeID, uint32 itemTypeID) const;

	void PushQuestWatchStatus(const QuestPrototype* pQuestProto, QUEST_STATUS questStatus);
	void PushQuestFinishStatus(QuestLog* pQuestLog);

	void PostInitAndUpdateQuests();

	void BuildCreatePacketForPlayer(INetPacket& pck, Player* pPlayer);

	std::string SaveQuests() const;
	std::string SaveQuestsDone() const;
	void LoadQuests(const std::string& data);
	void LoadQuestsDone(const std::string& data);

private:
	void TryTriggerEvent(
		QuestConditionType type, const std::function<bool(QuestLog*)>& func);

	bool IsQuestFinished4Repeatable(const QuestPrototype* pQuestProto) const;

	void AutoAcceptQuestInstance(uint32 questTypeID) const;
	void AutoSubmitQuestInstance(uint32 questUniqueKey) const;

	std::unordered_map<uint32, bool> DeflateFinishedQuests() const;
	void InflateFinishedQuests();

	Player* const m_pOwner;
	std::vector<QuestLog*> m_allQuestLog;

	bool m_isLevelDirty;
	std::unordered_set<uint32> m_allQuestStatusDirty;
	std::unordered_set<ChequeType> m_allChequeValueDirty;
	std::unordered_set<uint32> m_allItemCountDirty;

	std::unordered_map<uint32, QUEST_STATUS> m_allQuestWatchStatus;
	std::unordered_set<uint32> m_allAutoAcceptAvailQuests;
	std::unordered_set<uint32> m_allAutoSubmitAvailQuests;

	std::unordered_set<uint32> m_finishedQuests;
	std::unordered_map<uint32, size_t> m_finishedRepeatQuests[(int)QuestRepeatType::Count];
};
